%{

//#define DEBUG

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <postgresql/libpq-fe.h>
#include "end.h"

PGconn *psql;

int yylex(void);
void yyerror(char *str);

char* strclone(const char *str)
{
    char *ret = malloc(strlen(str)+1);
    strcpy(ret, str);
    return ret;
}

struct word_t {
    char *word, *type, *root;
    struct word_t *next;
};

struct word_t* new_word(char *word, char *type, char *root)
{
    struct word_t *w = malloc(sizeof(struct word_t));

    w->word = strclone(word);
    w->type = strclone(type);
    w->root = strclone(root);
    w->next = 0;

    return w;
}

struct sn_t {
    struct word_t *adj1, *nc, *adj2;
    struct word_t *pre1, *pre2, *sp;
    struct word_t *pre0, *conj;
    struct sn_t *next;
};

struct sn_t* new_sn()
{
    return calloc(1, sizeof(struct sn_t));
}

gdsl_list_t segmentos, list = 0;
word tmp_word = 0;

void print_sql(char *word)
{
    char *qry=NULL, sane[101];

    PQescapeString(sane, word, strlen(word));
    asprintf(&qry, "select genero,numero from palavra where palavra=lower('%s')"
        " and (genero is not null or numero is not null)", sane);
    PGresult *res = PQexec(psql, qry);

    char gen = '?';
    char num = '?';

    if (res && PQntuples(res) > 0) {
        gen = PQgetvalue(res, 0, 0)[0];
        num = PQgetvalue(res, 0, 1)[0];
    }

    PQclear(res);

    printf("(gen=%c num=%c gra=%c)", gen, num, 'n');

    tmp_word->genero = IND;
    if (gen == 'm') tmp_word->genero = MASCULINO;
    if (gen == 'f') tmp_word->genero = FEMININO;

    tmp_word->numero = IND;
    if (num == 's') tmp_word->numero = SINGULAR;
    if (num == 'p') tmp_word->numero = PLURAL;

    tmp_word->grau = IND;
    if (num == 'a') tmp_word->grau = AUMENTATIVO;
    if (num == 'd') tmp_word->grau = DIMINUTIVO;
    tmp_word->classificacao=SND;
}

void print_sn(struct sn_t *sn, int obj)
{
    struct word_t *w;

    if (!list) list = gdsl_list_alloc("", 0, 0);

    printf(obj ? "objeto:" : "sujeito:");

    for (; sn; sn = sn->next) {
        if (sn->pre0) printf(" %s :%s", sn->pre0->word, sn->pre0->type);
        if (sn->pre1) printf(" %s :%s", sn->pre1->word, sn->pre1->type);
        if (sn->pre2) printf(" %s :%s", sn->pre2->word, sn->pre2->type);
        if (sn->adj1) printf(" %s :%s", sn->adj1->word, sn->adj1->type);

        printf(" [");
        for (w = sn->nc; w; w = w->next){
            tmp_word = malloc(sizeof(Word));
            tmp_word->termo = strclone(w->word);
            tmp_word->classificacao = IND;
            tmp_word->funcao_sintatica = obj ? OBJETO : SUJEITO;
            
            if(w->type)
                printf(" %s :%s:", w->word, w->type);
            print_sql(w->word);

            gdsl_list_insert_tail(list, tmp_word);
            tmp_word = 0;
        }
        printf(" ]");

        if (sn->adj2) printf(" %s :%s", sn->adj2->word, sn->adj2->type);

        for (w = sn->sp; w; w = w->next)
            printf(" %s :%s", w->word, w->type);

        if (sn->conj) printf(" %s :%s", sn->conj->word, sn->conj->type);
    }
    printf("\n");
}

void print_oracao()
{
    if (!segmentos)
        segmentos = gdsl_list_alloc("palavras", 0, 0);

    if (list && gdsl_list_get_size(list) > 0)
        gdsl_list_insert_tail(segmentos, list);

    list = 0;
}

void printf2(const char *s)
{
#ifdef DEBUG
    printf(s);
#endif
}

%}

%token <w> VERBO PARTICIPIO NOME UNKNOWN
%token <w> PN_REL PN_PES PN_IND PN_DEM
%token <w> CO_SUB CO_COR
%token <w> ADJETIVO ARTIGO PREPOSICAO ADVERBIO
%token <w> PONTO VIRGULA

%type <w> adjetivo_ artigo_
%type <w> nomes nome
%type <sn> sn sn2 en

//%start texto

%union {
    struct word_t *w;
    struct sn_t *sn;
};

%%

texto:
    | texto2 texto
    ;

texto2:
    fim
    | frase fim
    | error { yyerrok; yyclearin; }
    ;

fim:
    PONTO {printf("fim oração\n");}
//    | VIRGULA
    ;

frase:
    oracao
    | oracao CO_COR oracao
    ;

oracao:
    oracao2          { print_oracao(); printf("--- oracao ---\n"); }
    | oracao2 error  { print_oracao(); printf("--- oracao error ---\n"); yyerrok; yyclearin; }
    ;

oracao2:
    sn sv               { print_sn($1, 0); printf2("oracao: sn sv\n"); }
    | sn                { print_sn($1, 0); printf2("oracao: sn\n"); } 
    | sv                {                  printf2("oracao: sv\n"); }
    ;

sv:
    sv2                { printf2("sv: sv\n"); }
    | sv2 CO_COR sv2   { printf2("sv: sv2 e sv2\n"); }
    | sv2 VIRGULA sv   { printf2("sv: sv2, sv\n"); } 
    ;

sv2:
    verbos              { printf2("sv: verbos\n"); }
    | verbos arg        { printf2("sv: verbos arg\n"); }
    | verbos arg arg    { printf2("sv: verbos arg arg\n"); }
    ;

verbos:
    verbos2
    | verbos2 ADVERBIO
    | ADVERBIO verbos2
    ;

verbos2:
    verbo verbos2
    | verbo
    ;

verbo:
    VERBO
    | PARTICIPIO
    ;

arg:
    arg2
    | PREPOSICAO arg2
    | PREPOSICAO verbos
//    | CO_COR PREPOSICAO arg2
    ;

arg2:
    sn                  { print_sn($1, 1); }
    ;

sn:
    sn2                         { $$ = $1; printf2("sn: sn2\n"); }
    | sn2 PN_REL sv             { $$ = $1; printf2("sn: sn2 PRONOME_RELATIVO sv\n"); }
    | sn2 PREPOSICAO sn2        { $$ = $1; $$->conj = $2; $$->next = $3; printf2("sn: sn2 PREPOSICAO sn2\n"); }
    | ARTIGO PN_REL sv          { $$ = new_sn(); printf2("sn: ARTIGO PRONOME_RELATIVO sv\n"); } 
    ;

sn2:
    artigo_ en                  { $$ = $2; $$->pre1 = $1;                    printf2("sn2: artigo? en\n"); }
    | artigo_ PN_IND            { $$ = new_sn(); $$->pre1 = $1; $$->nc = $2; printf2("sn2: artigo? PN_IND\n"); }
    | artigo_ PN_IND en         { $$ = $3; $$->pre1 = $1; $$->pre2 = $2;     printf2("sn2: artigo? PN_IND en\n"); }
    | PN_DEM en                 { $$ = $2; $$->pre1 = $1;                    printf2("sn2: PN_DEF en\n"); } 
    | PN_PES                    { $$ = new_sn(); $$->nc = $1;                printf2("sn2: PN_PE\n"); } 
    ;

en:
    adjetivo_ nomes adjetivo_ {
        $$ = new_sn();
        $$->adj1 = $1;
        $$->nc = $2;
        $$->adj2 = $3;
        printf2("en: adjetivo? nomes adjetivo?\n");
    }
    ;

nomes:
    nome nomes          { $$ = $1; $$->next = $2; }
    | nome              { $$ = $1; }
    ;

nome:
    NOME            { $$ = $1; }
    | UNKNOWN       { $$ = $1; }
    ;

artigo_:            { $$ = 0; }
    | ARTIGO        { $$ = $1; }
    ;

adjetivo_:          { $$ = 0; }
    | ADJETIVO      { $$ = $1; }
    ;

%%

struct {
    const char *str;
    int ret;
} types[] = {
    { "$,",    VIRGULA },
    { "</s>",    PONTO },
    { "V",    VERBO },
    { "_AP",    PARTICIPIO },
    { "N",    NOME },
    { "PROP",    NOME },
    { "ADJ",    ADJETIVO },
    { "PRP",    PREPOSICAO },
    { "DET",    ARTIGO },
    { "ADV",    ADVERBIO },
    { "PERS",    PN_REL },
    { "_CC",    CO_COR },
    { "_CS",    CO_SUB },
    { "PERS",    PN_DEM },
    { "PERS",    PN_PES },
    { "PERS",    PN_IND },
    { 0, 0 }
};

int yylex(void)
{
    char line[80];

    if (!fgets(line, 80, stdin)) return 0;
    puts(line);
//    char *word = strtok(line, " \n");
//    char *root = strtok(0, " \n");
//    char *type = strtok(0, " \n");

//    if (!word || !root || !type) return 0;

//    yylval.w = new_word(word, type, root);

#ifdef DEBUG
    printf("  %s %s\n", type, word);
#endif

    int i;
  //  for (i=0; types[i].str; i++)
  //      if (!strcmp(type, types[i].str))
  //          return types[i].ret;

    return UNKNOWN;
}

void yyerror(char *str)
{
#ifdef DEBUG
    puts(str);
#endif
}
#ifndef _PARSER
int main(int argc, char *argv[])
{
    psql = PQconnectdb("host='localhost' dbname='lexicon' user='sergio' password=''");
    if (!psql || PQstatus(psql) != CONNECTION_OK) {
        fprintf(stderr, "libpq error: %s\n", PQerrorMessage(psql));
        exit(0);
    }

    if(argc)
        stdin = fopen(argv[1],"r");
    printf("%s\n",argv[1]);
    yyparse();

    return 0;
}

#endif
